package com.lb.shopguide;

import android.app.Application;
import android.content.Context;
import android.support.multidex.MultiDex;
import android.text.TextUtils;

import com.blankj.utilcode.util.AppUtils;
import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.Utils;
import com.lb.shopguide.config.AppConfigManager;
import com.lb.shopguide.config.UserConfigManager;
import com.lb.shopguide.constants.AppConstant;
import com.lb.shopguide.http.ApiClient;
import com.lb.shopguide.http.ApiConstants;
import com.lb.shopguide.http.configuration.ApiConfiguration;
import com.lb.shopguide.im.Preference.Preferences;
import com.lb.shopguide.im.Preference.UserPreferences;
import com.lb.shopguide.im.online.DemoOnlineStateContentProvider;
import com.lb.shopguide.im.session.NimDemoLocationProvider;
import com.lb.shopguide.im.session.SessionHelper;
import com.lb.shopguide.util.ChannelUtil;
import com.lb.shopguide.util.lb.SystemUtil;
import com.netease.nim.uikit.api.NimUIKit;
import com.netease.nim.uikit.api.UIKitOptions;
import com.netease.nim.uikit.business.contact.core.query.PinYin;
import com.netease.nimlib.sdk.NIMClient;
import com.netease.nimlib.sdk.auth.LoginInfo;
import com.squareup.leakcanary.LeakCanary;
import com.tencent.bugly.Bugly;
import com.tencent.bugly.crashreport.CrashReport;
import com.tencent.tinker.loader.app.ApplicationLike;
import com.tendcloud.tenddata.TCAgent;
import com.tinkerpatch.sdk.TinkerPatch;
import com.tinkerpatch.sdk.loader.TinkerPatchApplicationLike;
import com.umeng.analytics.MobclickAgent;

import cn.jpush.android.api.JPushInterface;
import me.yokeyword.fragmentation.Fragmentation;
import me.yokeyword.fragmentation.helper.ExceptionHandler;


/**
 * Created by kang on 2017/5/15.
 */

public class GuideApplication extends Application {
    private UserConfigManager mUserConfigManager;

    private ApplicationLike tinkerApplicationLike;

    static Context _context;
    private static GuideApplication GuideApplication;


    public static Context getAppContext() {
        return GuideApplication;
    }

    public static synchronized GuideApplication context() {
        return (GuideApplication) _context;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        GuideApplication = this;
        _context = getApplicationContext();
        initLeakCanary();
        Utils.init(this);
        // CrashUtils.getInstance().init();
        initLog();
        //本地配置初始化
        mUserConfigManager = UserConfigManager.getInstance(this);
        AppConfigManager.getAppconfigManager(this);

        //提早初始化
        ApiConfiguration.Builder builder = ApiConfiguration.builder();
        if (AppConfigManager.getAppconfigManager(this).getDevMode() == AppConstant.KEY_RUN_MODE_FORMAL) {
            builder.dataSourceType(ApiConstants.DATA_FORMAL);
        } else {
            builder.dataSourceType(ApiConstants.DATA_DEVELOP);
        }
        ApiConfiguration apiConfiguration = builder.build();
        ApiClient.init(apiConfiguration);
//        HttpUrls.init(appConfigManager.getDevMode());
        //友盟数据分析
        initAnalysis();
        //云信im
        initIM();
        //bugly
        initBugly();
        //tinker热修复
        initTinkerPatch();
        //极光推送
        initPush();
        //talkingData集成
        initTD();
        //fragment栈
        initFragmentBall();
    }


    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        // you must install multiDex whatever tinker is installed!
        MultiDex.install(base);
    }

    private void initLeakCanary(){
        if (LeakCanary.isInAnalyzerProcess(this)) {
            // This process is dedicated to LeakCanary for heap analysis.
            // You should not init your app in this process.
            return;
        }
        LeakCanary.install(this);
    }

    private void initFragmentBall() {
        if (BuildConfig.DEBUG) {
            Fragmentation.builder()
                    // 设置 栈视图 模式为 悬浮球模式   SHAKE: 摇一摇唤出   NONE：隐藏
                    .stackViewMode(Fragmentation.BUBBLE)
                    // ture时，遇到异常："Can not perform this action after onSaveInstanceState!"时，会抛出
                    // false时，不会抛出，会捕获，可以在handleException()里监听到
                    .debug(BuildConfig.DEBUG)
                    // 线上环境时，可能会遇到上述异常，此时debug=false，不会抛出该异常（避免crash），会捕获
                    // 建议在回调处上传至我们的Crash检测服务器
                    .handleException(new ExceptionHandler() {
                        @Override
                        public void onException(Exception e) {
                            // 以Bugtags为例子: 手动把捕获到的 Exception 传到 Bugtags 后台。
                            // Bugtags.sendException(e);
                        }
                    })
                    .install();
        }
    }

    /**
     * 初始化分析
     */
    private void initAnalysis() {
        MobclickAgent.setDebugMode(BuildConfig.DEBUG);
//      SDK在统计Fragment时，需要关闭Activity自带的页面统计，
//		取消自动统计Activity
        MobclickAgent.openActivityDurationTrack(false);
        MobclickAgent.UMAnalyticsConfig config = new MobclickAgent.UMAnalyticsConfig(this, AppConstant.UMENG_APP_KEY, ChannelUtil.getChannel(this, AppConstant.DEFAULT_CHANNEL));
        MobclickAgent.startWithConfigure(config);
//		MobclickAgent.setAutoLocation(true);
//        当应用在后台运行超过5分钟（默认）再回到前端，将被认为是两个独立的session(启动),参数毫秒
//        MobclickAgent.setSessionContinueMillis(5 * 60 * 1000);
        //测试下，加密不加密区别
//        MobclickAgent.enableEncrypt(false);
    }

    private void initIM() {
        ImCache.setContext(this);
        NIMClient.init(this, getLoginInfo(), NimSDKOptionConfig.getSDKOptions(this));
        if (inMainProcess()) {
            // init pinyin
            PinYin.init(this);
            PinYin.validate();
            // 初始化UIKit模块
            initUIKit();
            // 初始化消息提醒
            NIMClient.toggleNotification(UserPreferences.getNotificationToggle());
            // 云信sdk相关业务初始化
            NIMInitManager.getInstance().init(true);
        }
    }

    public boolean inMainProcess() {
        String packageName = getPackageName();
        String processName = SystemUtil.getProcessName(this);
        return packageName.equals(processName);
    }

    private void initBugly() {
        Bugly.init(this, AppConstant.BUGLY_APPKEY, BuildConfig.DEBUG);
//        CrashReport.setIsDevelopmentDevice(this, BuildConfig.DEBUG);
        CrashReport.setAppChannel(getApplicationContext(), ChannelUtil.getChannel(this, AppConstant.DEFAULT_CHANNEL));
        CrashReport.setAppVersion(getApplicationContext(), AppUtils.getAppVersionName());
        CrashReport.initCrashReport(getApplicationContext(), AppConstant.BUGLY_APPKEY, BuildConfig.DEBUG);
    }

    private void initTinkerPatch() {
// 我们可以从这里获得Tinker加载过程的信息
        if (BuildConfig.TINKER_ENABLE) {
            tinkerApplicationLike = TinkerPatchApplicationLike.getTinkerPatchApplicationLike();
            // 初始化TinkerPatch SDK
            TinkerPatch.init(
                    tinkerApplicationLike
//                new TinkerPatch.Builder(tinkerApplicationLike)
//                    .requestLoader(new OkHttp3Loader())
//                    .build()
            )
                    .reflectPatchLibrary()
                    .setPatchRollbackOnScreenOff(true)
                    .setPatchRestartOnSrceenOff(true)
                    .setFetchPatchIntervalByHours(3);
            // 获取当前的补丁版本
            LogUtils.d("Current patch version is " + TinkerPatch.with().getPatchVersion());

            // fetchPatchUpdateAndPollWithInterval 与 fetchPatchUpdate(false)
            // 不同的是，会通过handler的方式去轮询
            TinkerPatch.with().fetchPatchUpdateAndPollWithInterval();
        }
    }

    private void initPush() {
        JPushInterface.setDebugMode(BuildConfig.DEBUG);    // 设置开启日志,发布时请关闭日志
        JPushInterface.init(this);            // 初始化 JPush
//        initPushNotification();
    }

//    private void initPushNotification() {
//        BasicPushNotificationBuilder builder = new BasicPushNotificationBuilder(this);
//        builder.statusBarDrawable = R.drawable.logo;
//        builder.notificationFlags = Notification.FLAG_AUTO_CANCEL;  //设置为点击后自动消失
//        builder.notificationDefaults = Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE
//                | Notification.DEFAULT_LIGHTS;  //设置为铃声（ Notification.DEFAULT_SOUND）或者震动（ Notification.DEFAULT_VIBRATE）
//        JPushInterface.setPushNotificationBuilder(1, builder);
//    }

    private void initTD() {
        TCAgent.LOG_ON = true;
        // App ID: 在TalkingData创建应用后，进入数据报表页中，在“系统设置”-“编辑应用”页面里查看App ID。
        // 渠道 ID: 是渠道标识符，可通过不同渠道单独追踪数据。
        TCAgent.init(this, AppConstant.TALKINGDATA_ID, ChannelUtil.getChannel(this, AppConstant.DEFAULT_CHANNEL));
        // 如果已经在AndroidManifest.xml配置了App ID和渠道ID，调用TCAgent.init(this)即可；或与AndroidManifest.xml中的对应参数保持一致。
        TCAgent.setReportUncaughtExceptions(true);
    }


    private void initLog() {
        final LogUtils.Config config = LogUtils.getConfig()
                .setLogSwitch(BuildConfig.DEBUG)// 设置 log 总开关，包括输出到控制台和文件，默认开
                .setConsoleSwitch(BuildConfig.DEBUG)// 设置是否输出到控制台开关，默认开
                .setGlobalTag(null)// 设置 log 全局标签，默认为空
                // 当全局标签不为空时，我们输出的 log 全部为该 tag，
                // 为空时，如果传入的 tag 为空那就显示类名，否则显示 tag
                .setLogHeadSwitch(true)// 设置 log 头信息开关，默认为开
                .setLog2FileSwitch(false)// 打印 log 时是否存到文件的开关，默认关
                .setDir("")// 当自定义路径为空时，写入应用的/cache/log/目录中
                .setFilePrefix("")// 当文件前缀为空时，默认为"util"，即写入文件为"util-MM-dd.txt"
                .setBorderSwitch(true)// 输出日志是否带边框开关，默认开
                .setConsoleFilter(LogUtils.V)// log 的控制台过滤器，和 logcat 过滤器同理，默认 Verbose
                .setFileFilter(LogUtils.V)// log 文件过滤器，和 logcat 过滤器同理，默认 Verbose
                .setStackDeep(1);// log 栈深度，默认为 1
        new Thread(new Runnable() {
            @Override
            public void run() {
                LogUtils.d(config.toString());
            }
        }).start();
    }

    private LoginInfo getLoginInfo() {
        String account = Preferences.getUserAccount();
        String token = Preferences.getUserToken();

        if (!TextUtils.isEmpty(account) && !TextUtils.isEmpty(token)) {
            ImCache.setAccount(account.toLowerCase());
            return new LoginInfo(account, token);
        } else {
            return null;
        }
    }


    private void initUIKit() {
        // 初始化，使用 uikit 默认的用户信息提供者
        NimUIKit.init(this, buildUIKitOptions());

        // 设置地理位置提供者。如果需要发送地理位置消息，该参数必须提供。如果不需要，可以忽略。
        NimUIKit.setLocationProvider(new NimDemoLocationProvider());

        // 会话窗口的定制初始化。
        SessionHelper.init();

        NimUIKit.setOnlineStateContentProvider(new DemoOnlineStateContentProvider());
    }


    private UIKitOptions buildUIKitOptions() {
        UIKitOptions options = new UIKitOptions();
        // 设置app图片/音频/日志等缓存目录
        options.appCacheDir = NimSDKOptionConfig.getAppCacheDir(this) + "/app";
        return options;
    }
}
